#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#define IOC_AT24CXX_READ  	100
#define IOC_AT24CXX_WRITE 	101
#define I2C_APP_DRV			1

typedef unsigned char   	u8;
typedef unsigned short   	u16;

int i2c_fd = 0;

// Write to an I2C slave device's register:
int i2c_write(u8 slave_addr, u16 reg, u8 data) 
{
    int retval;
    u8 outbuf[3];
 
    struct i2c_msg msgs[1];
    struct i2c_rdwr_ioctl_data msgset[1];
 
    outbuf[0] = (reg>>8)&0xFF;
	outbuf[1] = reg&0xFF;
    outbuf[2] = data;
 
    msgs[0].addr = slave_addr;
    msgs[0].flags = 0;
    msgs[0].len = 3;
    msgs[0].buf = outbuf;
 
    msgset[0].msgs = msgs;
    msgset[0].nmsgs = 1;
 
    if (ioctl(i2c_fd, I2C_RDWR, &msgset) < 0) {
        perror("ioctl(I2C_RDWR) in i2c_write !!!");
        return -1;
    }
 
    return 0;
}

// Read the given I2C slave device's register and return the read value in `*result`:
int i2c_read(u8 slave_addr, u16 reg, u8 *result) {
    int retval;
    u8 outbuf[2], inbuf[1];
    struct i2c_msg msgs[2];//这个地方要封两个包。因为要先写入需要读的地址，然后才是读操作
    struct i2c_rdwr_ioctl_data msgset[1];
 
    msgs[0].addr = slave_addr;
    msgs[0].flags = 0;//表示写
    msgs[0].len = 2;
    msgs[0].buf = outbuf;
 
    msgs[1].addr = slave_addr;
    msgs[1].flags |= I2C_M_RD;	//读
    msgs[1].len = 1;
    msgs[1].buf = inbuf;
 
    msgset[0].msgs = msgs;
    msgset[0].nmsgs = 2;
 
    outbuf[0] = (reg>>8)&0xFF;
	outbuf[1] = reg&0xFF;
 
    if (ioctl(i2c_fd, I2C_RDWR, &msgset) < 0) {
        perror("ioctl(I2C_RDWR) in i2c_read !!!\n");
        return -1;
    }
 
    *result = inbuf[0];
    return 0;
}

/*
 * file_execute	file_ops	   slave_addr
 * at24c02_test /dev/myat24c02 50
 * at24c02_test /dev/myat24c02 50
 */

int main(int argc, char **argv)
{
	u8 read_buf[2], write_buf[2];
	u16 count = 0;
	u8 slave_addr = 0, tmp_addr;
	int ret = 0;

	if ((argc != 3))
	{
		printf("Usage: %s <dev> <slave-addr>\n", argv[0]);
		return -1;
	}
	
	i2c_fd = open(argv[1], O_RDWR);
	if (i2c_fd < 0)
	{
		printf(" can not open %s\n", argv[1]);
		return -1;
	}

	tmp_addr = atoi(argv[2]);
	slave_addr |= (tmp_addr/10)<<4 | (tmp_addr%10);
	#ifdef I2C_APP_DRV
	ioctl(i2c_fd, I2C_TIMEOUT, 10);
    ioctl(i2c_fd, I2C_RETRIES, 2);
	#else
	if (ioctl(i2c_fd, I2C_SLAVE, slave_addr) < 0) {
		/* ERROR HANDLING; you can check errno to see what went wrong */
		return -1;
	}
	#endif

	for(;;) {
		if(count >= 255)
			count = 0;

		write_buf[0] = count; // reg addr
		write_buf[1] = count; // reg data

		#ifdef I2C_APP_DRV
		i2c_write(slave_addr, count, write_buf[1]);
		usleep(10000);	// 等待10ms
		i2c_read(slave_addr, count, read_buf);
		#else
		ret = write(i2c_fd, write_buf, 1);
		usleep(10000);	// 等待10ms
		read_buf[0] = count; // reg addr
		ret = read(i2c_fd, read_buf, 2);
		#endif

		if(read_buf[0] == write_buf[1])
			printf("eeprom@%#x : read[%#x] = write[%#x], count = %d\n", slave_addr, read_buf[0], write_buf[1], count);
		else
			printf("eeprom@%#x : read[%#x] != write[%#x], count = %d\n", slave_addr, read_buf[0], write_buf[1], count);
		
		memset(read_buf, 0, 2);
		count++;
		sleep(1);
	}

	#if 0
	if (argv[2][0] == 'r')
	{
		buf[0] = strtoul(argv[3], NULL, 0);
		ioctl(i2c_fd, IOC_AT24CXX_READ, buf);
		printf("Read addr 0x%x, get data 0x%x\n", buf[0], buf[1]);
	}
	else
	{
		buf[0] = strtoul(argv[3], NULL, 0);
		buf[1] = strtoul(argv[4], NULL, 0);
		ioctl(i2c_fd, IOC_AT24CXX_WRITE, buf);
	}
	#endif 

	close(i2c_fd);
	return 0;
}


